package ms.core.gateway.servlet;

import java.io.IOException;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import ms.core.common.ApiResult;
import ms.core.common.AppException;
import ms.core.common.consts.SysErr;
import ms.core.common.utils.ResponseUtils;
import ms.core.db.mysql.DbUtilsDrv;
import ms.core.gateway.dto.Api;
import ms.core.gateway.system.Application;
import ms.core.gateway.tool.ReflectTool;
import ms.core.tool.Log4j2Tool;

public class ServletExecutor implements Runnable{
	private Api api;				// api对象
	private AsyncContext context;	// 异步处理上下文

	public ServletExecutor(Api api, AsyncContext ctx) {
		this.api = api;
		this.context = ctx;
		//设置超时和执行侦听器
		this.context.setTimeout(300000L);
		this.context.addListener(new AsyncServletExecuteListener());
	}

	@Override
	public void run() {
		try {
			HttpServletRequest request = (HttpServletRequest) context.getRequest();
			HttpServletResponse response = (HttpServletResponse) context.getResponse();
			ackRequest(api, request, response);
			//调用complete方法，结束本次会话
			context.complete();
		} catch(Exception e) {
			Log4j2Tool.error(ServletExecutor.class, "异步servlet执行异常:", e);
		}
	}
	
	/**
	 * 响应servlet请求，接口返回出口
	 * 
	 * @param type
	 * @param func
	 * @param req
	 * @param resp
	 */
	public static void ackRequest(Api api, HttpServletRequest req, HttpServletResponse resp) {
		try {
			ApiResult ret = ReflectTool.call(api, req, resp);
			if (ret!=null) ResponseUtils.doResponse(resp, 200, ret);
		} catch(Exception e) {
			Throwable targetEx = e.getCause();
			if (targetEx==null) targetEx = e;
			if (targetEx instanceof AppException) {
				ResponseUtils.doResponse(resp, 403, new ApiResult(false, ((AppException) targetEx).getCode(), ((AppException) targetEx).getMsg()));
			} else {
				Log4j2Tool.error(ServletExecutor.class, "API调用异常", e);
				ResponseUtils.doResponse(resp, 500, new ApiResult(false, SysErr.SYS_UNKNOWN_ERR));
			}
		} finally {
			//关闭框架数据库连接
			DbUtilsDrv.closeSessionConnection();
			//关闭具体应用引入的资源
			if (Application.appDelegate!=null) Application.appDelegate.afterSessionEnded();
		}
	}
	
	public static class AsyncServletExecuteListener implements javax.servlet.AsyncListener{
		@Override
		public void onComplete(AsyncEvent event) throws IOException {
		}

		@Override
		public void onTimeout(AsyncEvent event) throws IOException {
		}

		@Override
		public void onError(AsyncEvent event) throws IOException {
		}

		@Override
		public void onStartAsync(AsyncEvent event) throws IOException {
		}
	}
}
